/*************************************************************************
    > File Name: network_utils.c
    > Author: Ykk
    > Mail: 3393579535@qq.com 
    > Created Time: 2023年05月20日 星期六 09时50分56秒
 ************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <strings.h>


void perr_exit(const char *s)
{
	perror(s);
	exit(-1);
}

int Accept(int fd,struct sockaddr *sa,socklen_t *salenptr)
{
	int n;
again:
	if((n = accept(fd,sa,salenptr)) < 0)
	{
		if((errno == ECONNABORTED) || (errno == EINTR))//如果是被信号层中断和软件层次中断
			goto again;
		else
			perr_exit("accept errno");
	}
	return n;
}

int Bind(int fd,const struct sockaddr *sa,socklen_t salen)
{
	int n;
	if((n = bind(fd,sa,salen)) < 0)
		perr_exit("bind errno");
	return n;
}

int Connect(int fd,const struct sockaddr *sa,socklen_t salen)
{
	int n;
	if((n = connect(fd,sa,salen)) < 0)
		perr_exit("connect errno");
	return n;
}

int Listen(int fd,int backlog)
{
	int n;

	if((n = listen(fd,backlog)) < 0)
		perr_exit("listen errno");
	return n;
}

int Socket(int family,int type,int protocol)
{
	int n;
	if((n = socket(family,type,protocol)) < 0)
		perr_exit("socket errno");
	return n;
}

ssize_t Read(int fd,void *ptr,size_t nbytes)
{
	ssize_t n;
again:
	if((n = read(fd,ptr,nbytes)) == -1)
	{
		if(errno == EINTR)//如果是被信号中断不应该退出
			goto again;
		else
			return -1;
	}
	return n;
}

ssize_t Write(int fd,const void *ptr,size_t nbytes)
{
	ssize_t n;
again:
	if((n = write(fd,ptr,nbytes)) == -1)
	{
		if(errno == EINTR)//如果是被信号中断不应该退出
			goto again;
		else
			return -1;
	}
	return n;
}

int Close(int fd)
{
	int n;
	if((n = close(fd)) == -1)
		perr_exit("close errno");
	return n;
}

/*读取固定的字节数*/
ssize_t Readn(int fd,void *vptr,size_t n)
{
	size_t nleft;          //usigned int 剩余未读取的字节数
	ssize_t nread;         //int 实际读取到的字节数
	char *ptr;        

	ptr = vptr;
	nleft = n;

	while(nleft > 0)
	{
		if((nread = read(fd,ptr,nleft)) < 0)
		{
			if(errno == EINTR)
				nread = 0;
			else
				return -1;
		}
		else if(nread == 0){
			break;
		}

		nleft -= nread;
		ptr += nread;
	}	
	return n - nleft;
}

/*写入固定的字节数*/
ssize_t Writen(int fd,const void *vptr,size_t n)
{
	size_t nleft;
	ssize_t nwritten;
	const char *ptr;

	ptr = vptr;
	nleft = n;
	while(nleft > 0)
	{
		if((nwritten = write(fd,ptr,nleft)) <= 0)
		{
			if(nwritten < 0 && errno == EINTR)
				nwritten = 0;
			else
				return -1;
		}

		nleft -= nwritten;
		ptr += nwritten;
	}
	return n;
}

static ssize_t my_read(int fd,char *ptr)
{
	static int read_cnt;
	static char *read_ptr;
	static char read_buf[100];

	if(read_cnt <= 0)
	{
again:
		if((read_cnt = read(fd,read_buf,sizeof(read_buf))) < 0)
		{
			if(errno == EINTR)
				goto again;
			return -1;
		}
		else if(read_cnt == 0)
			return 0;

		read_cnt--;
		*ptr = *read_ptr++;
	}
	return 1;
}

ssize_t Readline(int fd,void *vptr,size_t maxlen)
{
	ssize_t n,rc;
	char c,*ptr;

	ptr = vptr;
	for(n = 1;n < maxlen;n++)
	{
		if((rc = my_read(fd,&c)) == 1)
		{
			*ptr++ = c;
			if(c == '\n')
				break;
		}
		else if(rc == 0)
		{
			*ptr = 0;
			return n - 1;
		}
		else
			return -1;
	}
	*ptr = 0;

	return n;
}

int tcp4bind(short port,const char *IP)
{
	struct sockaddr_in serv_addr;
	int lfd = Socket(AF_INET,SOCK_STREAM,0);
	bzero(&serv_addr,sizeof(serv_addr));
	if(IP == NULL)
	{
		//如果这样使用 0.0.0.0,任意ip可任意连接
		serv_addr.sin_addr.s_addr = INADDR_ANY;
	}
	else
	{
		if(inet_pton(AF_INET,IP,&serv_addr.sin_addr.s_addr) <= 0)
		{
			perror("IP");//转化失败;
			exit(1);
		}
	}
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_port = htons(port);

	Bind(lfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr));
	return lfd;
}
